package com.nineclock.attendance.services.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.services.AttendGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.feign.OrganizationFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 黑马程序员
 * @Company http://www.ithiema.com
 * @Version 1.0
 */
@Service
@Slf4j
public class AttendGroupServiceImpl implements AttendGroupService {

    @Autowired
    AttendGroupMapper attendGroupMapper;

    @Autowired
    AttendGroupPartMapper attendGroupPartMapper;

    @Autowired
    OrganizationFeign organizationFeign;

    /**
     * 1. 判断企业是否是初次使用
     * 2. 如果是初次使用， 初始化 默认考勤组
     * 3. 分页查询考勤组列表
     * 4. 查询每个考勤组 关联的人数
     * 5. 组装数据
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {
        Long companyId = CurrentUserHolder.get().getCompanyId();
        //判断企业是否是初次使用(根据企业id查询考勤组个数)
        LambdaQueryWrapper<AttendGroup> attendGroupQw = new LambdaQueryWrapper<>();
        attendGroupQw.eq(AttendGroup::getCompanyId, companyId);
        Integer count = attendGroupMapper.selectCount(attendGroupQw);
        //如果为0 ，说明初次使用
        if(count  == 0){
            //初次使用，初始化默认考勤组(新增考勤组)
            AttendGroup attendGroup = this.buildDefaultAttendGroup();
            attendGroupMapper.insert(attendGroup);

            //维护考勤组和(顶级)部门的关系
            //查询当前企业下 顶级部门id
            List<Long> ids = organizationFeign.queryDepartmentIds().getData();
            if(CollectionUtil.isNotEmpty(ids)){
                for (Long id : ids) {
                    AttendGroupPart attendGroupPart = new AttendGroupPart();
                    attendGroupPart.setAttendGroupId(attendGroup.getId());  //考勤组id
                    attendGroupPart.setObjectType(1); //部门或者员工类型
                    attendGroupPart.setObjectId(id); // 部门或者员工id
                    attendGroupPart.setAttendType(1); // 是否参加考勤
                    attendGroupPartMapper.insert(attendGroupPart);
                }
            }

        }
        //分页查询考勤组列表
        Page<AttendGroup> attendGroupPage = new Page<>(page, pageSize);
        //分页查询
        attendGroupPage = attendGroupMapper.selectPage(attendGroupPage, attendGroupQw);
        //获取列表数据
        List<AttendGroup> attendGroupList = attendGroupPage.getRecords();
        if(CollectionUtil.isNotEmpty(attendGroupList)){
            List<AttendGroupDTO> attendGroupDTOList = BeanHelper.copyWithCollection(attendGroupList, AttendGroupDTO.class);
            for (AttendGroupDTO attendGroupDTO : attendGroupDTOList) {
                //查询考勤组 的关系
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
                attendGroupPartQw.eq(AttendGroupPart::getAttendGroupId, attendGroupDTO.getId());
                //考勤组关系列表
                List<AttendGroupPart> attendGroupParts = attendGroupPartMapper.selectList(attendGroupPartQw);

                //获取部门id集合
                List<Long> departmentIds = attendGroupParts.stream().filter(attendGroupPart -> {
                    boolean flag = attendGroupPart.getObjectType() == 1;
                    return flag;
                }).map(attendGroupPart -> {
                    return attendGroupPart.getObjectId();
                }).collect(Collectors.toList());

                //获取员工id集合
                List<Long> userIds = attendGroupParts.stream().filter(attendGroupPart -> {
                    boolean flag = attendGroupPart.getObjectType() == 2;
                    return flag;
                }).map(attendGroupPart -> {
                    return attendGroupPart.getObjectId();
                }).collect(Collectors.toList());


                //根据部门id集合获取 部门对应的人数
                Integer departmentMemberCount = organizationFeign.queryUserCountByDepartmentIds(departmentIds).getData();

                //查询每个考勤组对应的 人数

                attendGroupDTO.setMemberNum(departmentMemberCount + (userIds == null ? 0: userIds.size()));
            }
            PageResult<AttendGroupDTO> pageResult = new PageResult<>(
                    attendGroupPage.getTotal(), attendGroupPage.getPages(), attendGroupDTOList);
            return pageResult;
        }


        return new PageResult<>();
    }

    /**
     * 1. 新增考勤组
     * 2. 维护考勤组和部门、员工的关系
     *          判断部门或者员工是否与其他考勤组关联，如果关联删除关系， 再添加新的关系
     * @param attendGroupDTO
     */
    @Override
    public void addAttendGroup(AttendGroupDTO attendGroupDTO) {
        if(attendGroupDTO == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        //把dto中的数据赋值给 pojo
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        //设置 工作日
        String workdays = StrUtil.join(",", attendGroupDTO.getWorkdays());
        attendGroup.setWorkdays(workdays);

        //设置无需打卡的日期， 必须打卡的日期
        List<AttendGroupPCExtraConfigDTO> extraConfig = attendGroupDTO.getExtraConfig();
        //必须打卡的日期
        List<String> necessaryTime = extraConfig.stream().filter(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend() == 1;
        }).map(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getSetDate();
        }).collect(Collectors.toList());

        //无须打卡的日期
        List<String> unnecessaryTime = extraConfig.stream().filter(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend() == 0;
        }).map(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getSetDate();
        }).collect(Collectors.toList());

        //设置需要打卡和无需打卡的日期列表
        attendGroup.setNecessaryTimeList(StrUtil.join(",", necessaryTime));
        attendGroup.setUnnecessaryTimeList(StrUtil.join(",", unnecessaryTime));

        //其他的基础字段
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());


        attendGroupMapper.insert(attendGroup);

        //关系维护（参与考勤的人员，无需参与考勤的人员）
        //参与考勤的人员
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();
        if(CollectionUtil.isNotEmpty(participates)){
            for (AttendGroupPartDTO participate : participates) {
                //删除原来的关系
                LambdaQueryWrapper<AttendGroupPart> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(AttendGroupPart::getObjectType, participate.getObjectType());
                wrapper.eq(AttendGroupPart::getObjectId, participate.getObjectId());
                attendGroupPartMapper.delete(wrapper);

                //添加新的关系
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId()); // 关联新的考勤组
                attendGroupPart.setAttendType(1); // 是否参与考勤
                attendGroupPart.setObjectType(participate.getObjectType()); // 类型：部门或者员工
                attendGroupPart.setObjectId(participate.getObjectId());  //部门或者员工的id

                attendGroupPartMapper.insert(attendGroupPart);
            }
        }


        //无需参与考勤的人员
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();
        if(CollectionUtil.isNotEmpty(notParticipates)){
            for (AttendGroupPartDTO participate : notParticipates) {
                //删除原来的关系
                LambdaQueryWrapper<AttendGroupPart> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(AttendGroupPart::getObjectType, participate.getObjectType());
                wrapper.eq(AttendGroupPart::getObjectId, participate.getObjectId());
                attendGroupPartMapper.delete(wrapper);

                //添加新的关系
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId()); // 关联新的考勤组
                attendGroupPart.setAttendType(2); // 是否参与考勤
                attendGroupPart.setObjectType(participate.getObjectType()); // 类型：部门或者员工
                attendGroupPart.setObjectId(participate.getObjectId());  //部门或者员工的id

                attendGroupPartMapper.insert(attendGroupPart);
            }
        }




    }

    /**
     * 1. 从认证信息中获取员工id
     * 2. 根据员工获取员工关联考勤组
     * 3. 如果查不到考勤组， 查询该员工关联部门id
     * 4. 根据部门id 查询关联考勤组
     * 5. 根据部门id获取部门信息
     *
     * @return
     */
    @Override
    public AttendGroupDTO getAttendGroupByUserId() {
        //获取员工id
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();

        //获取该员工与考勤组的关系
        LambdaQueryWrapper<AttendGroupPart> attendGroupPartQw = new LambdaQueryWrapper<>();
        attendGroupPartQw.eq(AttendGroupPart::getObjectType, 2);
        attendGroupPartQw.eq(AttendGroupPart::getObjectId, companyUserId);
        AttendGroupPart attendGroupPart = attendGroupPartMapper.selectOne(attendGroupPartQw);
        //如果没有查询到 员工与考勤组的关系， 根据部门再来查询考勤组
        if(attendGroupPart == null){
            //查询该员工所在的部门id 集合
            List<Long> departmentIds = organizationFeign.queryDepartmentsByUserId(companyUserId).getData();
            if(CollectionUtil.isNotEmpty(departmentIds)){
                for (Long departmentId : departmentIds) {
                    LambdaQueryWrapper<AttendGroupPart> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(AttendGroupPart::getObjectType, 1);
                    wrapper.eq(AttendGroupPart::getObjectId, departmentId);
                    attendGroupPart = attendGroupPartMapper.selectOne(wrapper);
                    if(attendGroupPart != null){
                        break;
                    }
                }
            }
        }

        if(attendGroupPart != null){
            Long attendGroupId = attendGroupPart.getAttendGroupId();
            AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupId);
            AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);
            //需要对考勤组中的工作日字段进行转换
            String workdays = attendGroup.getWorkdays();
            //把字符串转换为list集合
            String[] split = workdays.split(",");
            List<String> list = Arrays.asList(split);
            attendGroupDTO.setWorkdays(list);

            return attendGroupDTO;
        }

        return null;
    }

    //构建默认考勤组
    public AttendGroup buildDefaultAttendGroup(){
        Long companyId = CurrentUserHolder.get().getCompanyId();
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("默认考勤组");
        attendGroup.setCompanyId(companyId);
        attendGroup.setStartWorkTime("09:00:00");
        attendGroup.setAllowLateMinutes(10);
        attendGroup.setLateMinutes(30);
        attendGroup.setStartNoonRestTime("12:00:00");
        attendGroup.setEndNoonRestTime("14:00:00");
        attendGroup.setOffWorkTime("17:00:00");
        attendGroup.setWorkdays("1,1,1,1,1,0,0");
        attendGroup.setAddress("北京市昌平区建材城西路9号金燕龙教学楼");
        attendGroup.setLat(new BigDecimal(116.34336800000000000000));
        attendGroup.setLng(new BigDecimal(40.06045600000000000000));
        attendGroup.setAddressRange(1000);
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId()); //创建者
        attendGroup.setCreateTime(new Date());
        attendGroup.setAddressName("金燕龙总部");
        return  attendGroup;
    }
}
